﻿
using System;

namespace UdpPublisher
{
    //============================================================//
    #region [ publish generator base ]

    abstract class PubGeneratorBase : IDisposable
    {
        public delegate void PublishChannel(byte[] pubContent, int offset, int length);

        private PublishChannel m_publishChannel;

        public void AddPublishChannel(PublishChannel channel)
        {
            m_publishChannel += channel;
        }

        protected void PublishOut(byte[] pubContent, int offset, int length)
        {
            if (m_publishChannel != null)
                m_publishChannel(pubContent, offset, length);
        }

        public abstract void Dispose();
        public abstract void Start();
    }

    #endregion

    //============================================================//
    #region [ timer publisher ]

    class TimerPublisher : PubGeneratorBase
    {
        //=========================================================//
        #region [ member variables ]

        public delegate byte[] MakeContentDelegate();

        private System.Timers.Timer m_timer;
        private MakeContentDelegate m_contentMaker;

        private bool m_disposed = false;

        #endregion

        //=========================================================//
        #region [ constructor and destructor ]

        public TimerPublisher(int interval, MakeContentDelegate contentMaker)
        {
            m_timer = new System.Timers.Timer();
            m_timer.Interval = interval;
            m_timer.Elapsed += OnTimeout;

            m_contentMaker = contentMaker;
        }

        ~TimerPublisher()
        {
            Dispose(false);
        }

        #endregion 

        //=========================================================//
        #region [ public methods ]

        public override void Start()
        {
            m_timer.Start();
        }

        public override void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion

        //=========================================================//
        #region [ private methods ]

        private void OnTimeout(object source, EventArgs evtargs)
        {
            byte[] pubContent = m_contentMaker();
            PublishOut(pubContent, 0, pubContent.Length);
        }

        private void Dispose(bool isDisposing)
        {
            if (m_disposed)
                return;

            try
            {
                if (isDisposing)
                {
                    m_timer.Stop();
                    m_timer.Dispose();
                }
            }
            finally
            {
                m_disposed = true;
            }
        }

        #endregion
    }

    #endregion
}
